package evl

import (
	"fmt"

	"gitcode.com/deyiyangyang/bampoo/ast"
	"gitcode.com/deyiyangyang/bampoo/obj"
)

// Evaluator represents a Scheme evaluator
type Evaluator struct {
	env *obj.Environment
}

// New creates a new evaluator
func New(env *obj.Environment) *Evaluator {
	return &Evaluator{env: env}
}

// Eval evaluates an expression
func (e *Evaluator) Eval(expr interface{}) (obj.Value, error) {
	switch node := expr.(type) {
	case *ast.Program:
		return e.evalProgram(node)
	case *ast.StringLiteral:
		return e.evalStringLiteral(node)
	case *ast.IntegerLiteral:
		return &obj.IntegerValue{Value: node.Value}, nil
	case *ast.RealLiteral:
		return &obj.RealValue{Value: node.Value}, nil
	case *ast.BooleanLiteral:
		return &obj.BooleanValue{Value: node.Value}, nil
	case *ast.Symbol:
		return e.evalSymbol(node)
	case *ast.DefineExpr:
		return e.evalDefine(node)
	case *ast.SetExpr:
		return e.evalSet(node)
	case *ast.DisplayExpr:
		return e.evalDisplay(node)
	case *ast.BeginExpr:
		return e.evalBegin(node)
	case *ast.List:
		return e.evalList(node)
	case *ast.ArithmeticExpr:
		return e.evalArithmetic(node)
	case *ast.LambdaExpr:
		return e.evalLambda(node)
	case *ast.LetExpr:
		return e.evalLet(node)
	case *ast.FunctionCall:
		return e.evalFunctionCall(node)
	case *ast.IfExpr:
		return e.evalIf(node)
	case *ast.CondExpr:
		return e.evalCond(node)
	case *ast.ComparisonExpr:
		return e.evalComparison(node)
	case *ast.LogicalExpr:
		return e.evalLogical(node)
	case *ast.QuoteExpr:
		return e.evalQuote(node)
	default:
		return nil, fmt.Errorf("unknown expression type: %T", expr)
	}
}

// This function is no longer used due to the fix in Eval method
// func (e *Evaluator) evalExpression(expr ast.Expression) (obj.Value, error) {
// 	switch node := expr.(type) {
// 	case *ast.StringLiteral:
// 		return &obj.StringValue{Value: node.Value}, nil
// 	case *ast.IntegerLiteral:
// 		return &obj.IntegerValue{Value: node.Value}, nil
// 	case *ast.Symbol:
// 		return e.evalSymbol(node)
// 	case *ast.DefineExpr:
// 		return e.evalDefine(node)
// 	case *ast.DisplayExpr:
// 		return e.evalDisplay(node)
// 	case *ast.BeginExpr:
// 		return e.evalBegin(node)
// 	case *ast.List:
// 		return e.evalList(node)
// 	case *ast.ArithmeticExpr:
// 		return e.evalArithmetic(node)
// 	case *ast.LambdaExpr:
// 		return e.evalLambda(node)
// 	case *ast.FunctionCall:
// 		return e.evalFunctionCall(node)
// 	default:
// 		return nil, fmt.Errorf("unknown expression type: %T", expr)
// 	}
// }

func (e *Evaluator) evalProgram(program *ast.Program) (obj.Value, error) {
	var result obj.Value = &obj.NilValue{}
	var err error

	for _, expr := range program.Expressions {
		result, err = e.Eval(expr)
		if err != nil {
			return nil, err
		}
	}

	return result, nil
}

// evalIf evaluates an if expression
// (if condition consequence alternative)
func (e *Evaluator) evalIf(node *ast.IfExpr) (obj.Value, error) {
	// Evaluate the condition
	conditionValue, err := e.Eval(node.Condition)
	if err != nil {
		return nil, err
	}

	// Determine if the condition is "true"
	// In Scheme, only #f (false) and () (empty list) are considered false
	conditionIsTrue := conditionValue != nil
	if booleanValue, ok := conditionValue.(*obj.BooleanValue); ok {
		conditionIsTrue = booleanValue.Value
	} else {
		conditionIsTrue = conditionValue != nil && !(conditionValue == (*obj.NilValue)(nil))
	}

	// Evaluate the appropriate branch
	if conditionIsTrue {
		return e.Eval(node.Consequence)
	} else if node.Alternative != nil {
		return e.Eval(node.Alternative)
	}

	// If no alternative and condition is false, return nil
	return &obj.NilValue{}, nil
}

// evalCond evaluates a cond expression
// (cond (test1 expr1) (test2 expr2) ... (else exprN))
func (e *Evaluator) evalCond(node *ast.CondExpr) (obj.Value, error) {
	for _, clause := range node.Clauses {
		// For else clause, always evaluate
		if clause.IsElse {
			return e.Eval(clause.Result)
		}

		// Evaluate the test expression
		testValue, err := e.Eval(clause.Test)
		if err != nil {
			return nil, err
		}

		// Check if the test is "true"
		testIsTrue := testValue != nil
		if booleanValue, ok := testValue.(*obj.BooleanValue); ok {
			testIsTrue = booleanValue.Value
		} else {
			testIsTrue = testValue != nil && !(testValue == (*obj.NilValue)(nil))
		}

		if testIsTrue {
			return e.Eval(clause.Result)
		}
	}

	// If no clause matched and no else clause, return nil
	return &obj.NilValue{}, nil
}

// evalComparison evaluates a comparison expression
// (> expr1 expr2), (< expr1 expr2), etc.
func (e *Evaluator) evalComparison(node *ast.ComparisonExpr) (obj.Value, error) {
	// Make sure there are at least 2 operands
	if len(node.Operands) < 2 {
		return nil, fmt.Errorf("comparison operator '%s' requires at least 2 operands", node.Operator)
	}

	// Validate operator
	supportedOperators := map[string]bool{
		">": true,
		"<": true,
		"=": true,
		">=": true,
		"<=": true,
	}
	if !supportedOperators[node.Operator] {
		return nil, fmt.Errorf("unknown comparison operator")
	}

	// Evaluate all operands
	var values []obj.Value
	for _, operand := range node.Operands {
		value, err := e.Eval(operand)
		if err != nil {
			return nil, err
		}
		values = append(values, value)
	}

	// Perform the comparison
	result := true
	for i := 0; i < len(values)-1; i++ {
		v1 := values[i]
		v2 := values[i+1]

		// Compare based on type
		var compareResult bool
		switch n1 := v1.(type) {
		case *obj.IntegerValue:
			switch n2 := v2.(type) {
			case *obj.IntegerValue:
				compareResult = e.compareIntegers(n1, n2, node.Operator)
			case *obj.RationalValue:
				// Convert integer to rational and compare
				r1 := &obj.RationalValue{Numerator: n1.Value, Denominator: 1}
				compareResult = e.compareRationals(r1, n2, node.Operator)
			case *obj.RealValue:
				// Convert integer to real and compare
				compareResult = e.compareReals(float64(n1.Value), n2.Value, node.Operator)
			default:
				return nil, fmt.Errorf("cannot perform comparison '%s' on non-numeric values", node.Operator)
			}
		case *obj.RationalValue:
			switch n2 := v2.(type) {
			case *obj.IntegerValue:
				// Convert integer to rational and compare
				r2 := &obj.RationalValue{Numerator: n2.Value, Denominator: 1}
				compareResult = e.compareRationals(n1, r2, node.Operator)
			case *obj.RationalValue:
				compareResult = e.compareRationals(n1, n2, node.Operator)
			case *obj.RealValue:
				// Convert rational to real and compare
				r1 := float64(n1.Numerator) / float64(n1.Denominator)
				compareResult = e.compareReals(r1, n2.Value, node.Operator)
			default:
				return nil, fmt.Errorf("cannot perform comparison '%s' on non-numeric values", node.Operator)
			}
		case *obj.RealValue:
			switch n2 := v2.(type) {
			case *obj.IntegerValue:
				// Convert integer to real and compare
				compareResult = e.compareReals(n1.Value, float64(n2.Value), node.Operator)
			case *obj.RationalValue:
				// Convert rational to real and compare
				r2 := float64(n2.Numerator) / float64(n2.Denominator)
				compareResult = e.compareReals(n1.Value, r2, node.Operator)
			case *obj.RealValue:
				compareResult = e.compareReals(n1.Value, n2.Value, node.Operator)
			default:
				return nil, fmt.Errorf("cannot perform comparison '%s' on non-numeric values", node.Operator)
			}
		default:
			return nil, fmt.Errorf("cannot perform comparison '%s' on non-numeric values", node.Operator)
		}

		// Update the overall result
		result = result && compareResult

		// For chained comparisons, all must be true
		if !result {
			break
		}
	}

	// Return boolean value
	if result {
		return &obj.BooleanValue{Value: true}, nil
	} else {
		return &obj.BooleanValue{Value: false}, nil
	}
}

// compareIntegers compares two integers based on the operator
func (e *Evaluator) compareIntegers(n1, n2 *obj.IntegerValue, operator string) bool {
	switch operator {
	case ">" :
		return n1.Value > n2.Value
	case "<" :
		return n1.Value < n2.Value
	case "=" :
		return n1.Value == n2.Value
	case ">=" :
		return n1.Value >= n2.Value
	case "<=" :
		return n1.Value <= n2.Value
	default :
		return false
	}
}

// compareRationals compares two rational numbers based on the operator
func (e *Evaluator) compareRationals(r1, r2 *obj.RationalValue, operator string) bool {
	// Cross multiply to avoid floating point inaccuracies
	num1 := r1.Numerator * r2.Denominator
	num2 := r2.Numerator * r1.Denominator
	switch operator {
	case ">" :
		return num1 > num2
	case "<" :
		return num1 < num2
	case "=" :
		return num1 == num2
	case ">=" :
		return num1 >= num2
	case "<=" :
		return num1 <= num2
	default :
		return false
	}
}

// compareReals compares two real numbers based on the operator
func (e *Evaluator) compareReals(r1, r2 float64, operator string) bool {
	switch operator {
	case ">" :
		return r1 > r2
	case "<" :
		return r1 < r2
	case "=" :
		return r1 == r2
	case ">=" :
		return r1 >= r2
	case "<=" :
		return r1 <= r2
	default :
		return false
	}
}

// evalLogical evaluates a logical expression
// (and expr1 expr2 ...), (or expr1 expr2 ...), (not expr)
func (e *Evaluator) evalLogical(node *ast.LogicalExpr) (obj.Value, error) {
	switch node.Operator {
	case "and":
		// (and) returns true
		if len(node.Operands) == 0 {
			return &obj.BooleanValue{Value: true}, nil
		}

		// Evaluate each operand
		for _, operand := range node.Operands {
			value, err := e.Eval(operand)
			if err != nil {
				return nil, err
			}

			// Check if the value is "false"
			valueIsTrue := value != nil
			if booleanValue, ok := value.(*obj.BooleanValue); ok {
				valueIsTrue = booleanValue.Value
			} else {
				valueIsTrue = value != nil && !(value == (*obj.NilValue)(nil))
			}

			if !valueIsTrue {
				return &obj.BooleanValue{Value: false}, nil // Return false if any operand is false
			}
		}

		return &obj.BooleanValue{Value: true}, nil // Return true if all operands are true

	case "or":
		// (or) returns false
		if len(node.Operands) == 0 {
			return &obj.BooleanValue{Value: false}, nil
		}

		// Evaluate each operand
		for _, operand := range node.Operands {
			value, err := e.Eval(operand)
			if err != nil {
				return nil, err
			}

			// Check if the value is "true"
			valueIsTrue := value != nil
			if booleanValue, ok := value.(*obj.BooleanValue); ok {
				valueIsTrue = booleanValue.Value
			} else {
				valueIsTrue = value != nil && !(value == (*obj.NilValue)(nil))
			}

			if valueIsTrue {
				return &obj.BooleanValue{Value: true}, nil // Return true if any operand is true
			}
		}

		return &obj.BooleanValue{Value: false}, nil // Return false if all operands are false

	case "not":
		// (not expr) requires exactly one operand
		if len(node.Operands) != 1 {
			return nil, fmt.Errorf("not requires exactly one operand")
		}

		value, err := e.Eval(node.Operands[0])
		if err != nil {
			return nil, err
		}

		// Check if the value is "false"
		valueIsTrue := value != nil
		if booleanValue, ok := value.(*obj.BooleanValue); ok {
			valueIsTrue = booleanValue.Value
		} else {
			valueIsTrue = value != nil && !(value == (*obj.NilValue)(nil))
		}

		if !valueIsTrue {
			return &obj.BooleanValue{Value: true}, nil // not false is true
		} else {
			return &obj.BooleanValue{Value: false}, nil // not true is false
		}

	default:
		return nil, fmt.Errorf("unknown logical operator: %s", node.Operator)
	}

	return &obj.NilValue{}, nil
}

// valuesEqual checks if two values are equal
func (e *Evaluator) valuesEqual(v1, v2 obj.Value) bool {
	// Handle nil values
	if v1 == nil && v2 == nil {
		return true
	} else if v1 == nil || v2 == nil {
		return false
	}

	// Handle booleans
	if b1, ok1 := v1.(*obj.BooleanValue); ok1 {
		if b2, ok2 := v2.(*obj.BooleanValue); ok2 {
			return b1.Value == b2.Value
		}
	}

	// Handle numeric values with type conversions
	switch n1 := v1.(type) {
	case *obj.IntegerValue:
		switch n2 := v2.(type) {
		case *obj.IntegerValue:
			return n1.Value == n2.Value
		case *obj.RationalValue:
				// Convert integer to rational and compare
				r1 := &obj.RationalValue{Numerator: n1.Value, Denominator: 1}
				return e.compareRationals(r1, n2, "=")
		case *obj.RealValue:
			// Convert integer to real and compare
			return float64(n1.Value) == n2.Value
		}
	case *obj.RationalValue:
		switch n2 := v2.(type) {
		case *obj.IntegerValue:
			// Convert integer to rational and compare
			r2 := &obj.RationalValue{Numerator: n2.Value, Denominator: 1}
			return e.compareRationals(n1, r2, "=")
		case *obj.RationalValue:
			return e.compareRationals(n1, n2, "=")
		case *obj.RealValue:
			// Convert rational to real and compare
			r1 := float64(n1.Numerator) / float64(n1.Denominator)
			return r1 == n2.Value
		}
	case *obj.RealValue:
		switch n2 := v2.(type) {
		case *obj.IntegerValue:
			// Convert integer to real and compare
			return n1.Value == float64(n2.Value)
		case *obj.RationalValue:
				// Convert rational to real and compare
				r2 := float64(n2.Numerator) / float64(n2.Denominator)
				return n1.Value == r2
		case *obj.RealValue:
			return n1.Value == n2.Value
		}
	}

	// Handle strings
	if s1, ok1 := v1.(*obj.StringValue); ok1 {
		if s2, ok2 := v2.(*obj.StringValue); ok2 {
			return s1.Value == s2.Value
		}
	}

	// Handle nil values
	if _, ok1 := v1.(*obj.NilValue); ok1 {
		if _, ok2 := v2.(*obj.NilValue); ok2 {
			return true
		}
	}

	// For other types, consider them equal only if they're the same reference
	return v1 == v2
}

func (e *Evaluator) evalStringLiteral(sl *ast.StringLiteral) (obj.Value, error) {
	return &obj.StringValue{Value: sl.Value}, nil
}

func (e *Evaluator) evalSymbol(sym *ast.Symbol) (obj.Value, error) {
	value, ok := e.env.Get(sym.Value)
	if !ok {
		return nil, fmt.Errorf("undefined symbol: %s", sym.Value)
	}
	return value, nil
}

func (e *Evaluator) evalDefine(define *ast.DefineExpr) (obj.Value, error) {
	value, err := e.Eval(define.Value)
	if err != nil {
		return nil, err
	}

	// If we're defining a function, mark it as being stored in environment
	// to help with circular reference detection
	if funcVal, ok := value.(*obj.FunctionValue); ok {
		funcVal.InEnvironment = true
	}

	e.env.Set(define.Name.Value, value)
	return &obj.NilValue{}, nil
}

func (e *Evaluator) evalSet(set *ast.SetExpr) (obj.Value, error) {
	// Check if the variable exists
	_, ok := e.env.Get(set.Name.Value)
	if !ok {
		return nil, fmt.Errorf("cannot set! undefined variable: %s", set.Name.Value)
	}

	// Evaluate the new value
	value, err := e.Eval(set.Value)
	if err != nil {
		return nil, err
	}

	// Update the variable
	e.env.Set(set.Name.Value, value)
	return &obj.NilValue{}, nil
}

func (e *Evaluator) evalDisplay(display *ast.DisplayExpr) (obj.Value, error) {
	value, err := e.Eval(display.Value)
	if err != nil {
		return nil, err
	}
	fmt.Print(value.String())
	return &obj.NilValue{}, nil
}

func (e *Evaluator) evalBegin(begin *ast.BeginExpr) (obj.Value, error) {
	var result obj.Value = &obj.NilValue{}
	var err error

	// Evaluate each expression in order
	for _, expr := range begin.Body {
		result, err = e.Eval(expr)
		if err != nil {
			return nil, err
		}
	}

	// Return the result of the last expression
	return result, nil
}

func (e *Evaluator) evalLet(let *ast.LetExpr) (obj.Value, error) {
	// Create new environment for let bindings
	newEnv := obj.NewEnclosedEnvironment(e.env)

	// Evaluate bindings in the current environment
	for _, binding := range let.Bindings {
		value, err := e.Eval(binding.Value)
		if err != nil {
			return nil, err
		}
		newEnv.Set(binding.Name.Value, value)
	}

	// Switch to the new environment for body evaluation
	oldEnv := e.env
	e.env = newEnv
	defer func() {
		e.env = oldEnv
	}()

	// Evaluate body expressions
	var result obj.Value = &obj.NilValue{}
	var err error
	for _, expr := range let.Body {
		result, err = e.Eval(expr)
		if err != nil {
			return nil, err
		}
	}

	return result, nil
}

func (e *Evaluator) evalList(list *ast.List) (obj.Value, error) {
	if len(list.Elements) == 0 {
		return &obj.NilValue{}, nil
	}

	// Convert list to function call
	functionCall := &ast.FunctionCall{
		Function:  list.Elements[0],
		Arguments: list.Elements[1:],
	}

	return e.evalFunctionCall(functionCall)
}

// gcd calculates the greatest common divisor of two integers
func gcd(a, b int64) int64 {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

// reduceRational reduces a rational number to its simplest form
func reduceRational(numerator, denominator int64) (int64, int64) {
	// Handle sign
	sign := int64(1)
	if numerator < 0 {
		sign *= -1
		numerator *= -1
	}
	if denominator < 0 {
		sign *= -1
		denominator *= -1
	}

	// Calculate GCD and reduce
	g := gcd(numerator, denominator)
	numerator /= g
	denominator /= g

	// Apply sign to numerator
	numerator *= sign

	return numerator, denominator
}

func (e *Evaluator) evalArithmetic(expr *ast.ArithmeticExpr) (obj.Value, error) {
	if len(expr.Operands) == 0 {
		return nil, fmt.Errorf("arithmetic expression requires at least one operand")
	}

	// For division, we need to handle fractions specially
	if expr.Operator == "/" {
		// First evaluate the numerator
		numeratorValue, err := e.Eval(expr.Operands[0])
		if err != nil {
			return nil, err
		}

		// Evaluate each denominator operand
		for i := 1; i < len(expr.Operands); i++ {
			currentValue, err := e.Eval(expr.Operands[i])
			if err != nil {
				return nil, err
			}

			// Check for division by zero
			switch v := currentValue.(type) {
			case *obj.IntegerValue:
				if v.Value == 0 {
					return nil, fmt.Errorf("division by zero")
				}
			case *obj.RationalValue:
				if v.Numerator == 0 {
					return nil, fmt.Errorf("division by zero")
				}
			case *obj.RealValue:
				if v.Value == 0 {
					return nil, fmt.Errorf("division by zero")
				}
			}

			// Handle division based on types
			switch num := numeratorValue.(type) {
			case *obj.IntegerValue:
				switch denom := currentValue.(type) {
				case *obj.IntegerValue:
					// Integer division - return fraction if not divisible
					if num.Value%denom.Value == 0 {
						// Exactly divisible, return integer
						numeratorValue = &obj.IntegerValue{Value: num.Value / denom.Value}
					} else {
						// Not divisible, return reduced rational number
					numReduced, denomReduced := reduceRational(num.Value, denom.Value)
					numeratorValue = &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
					}
				case *obj.RationalValue:
				// Integer divided by rational = integer * reciprocal rational
				numReduced, denomReduced := reduceRational(num.Value*denom.Denominator, denom.Numerator)
				numeratorValue = &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
				case *obj.RealValue:
					// Convert to real number
					numeratorValue = &obj.RealValue{Value: float64(num.Value) / denom.Value}
				}
			case *obj.RationalValue:
			switch denom := currentValue.(type) {
			case *obj.IntegerValue:
				// Rational divided by integer = rational * 1/integer
				numReduced, denomReduced := reduceRational(num.Numerator, num.Denominator*denom.Value)
				numeratorValue = &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
			case *obj.RationalValue:
				// Rational divided by rational = rational * reciprocal rational
				numReduced, denomReduced := reduceRational(num.Numerator*denom.Denominator, num.Denominator*denom.Numerator)
				numeratorValue = &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
			case *obj.RealValue:
				// Convert to real number
				rationalValue := float64(num.Numerator) / float64(num.Denominator)
				numeratorValue = &obj.RealValue{Value: rationalValue / denom.Value}
			}
			case *obj.RealValue:
				switch denom := currentValue.(type) {
				case *obj.IntegerValue:
					// Real divided by integer
					numeratorValue = &obj.RealValue{Value: num.Value / float64(denom.Value)}
				case *obj.RationalValue:
				// Real divided by rational = real * reciprocal rational
				rationalValue := float64(denom.Denominator) / float64(denom.Numerator)
				numeratorValue = &obj.RealValue{Value: num.Value * rationalValue}
				case *obj.RealValue:
					// Real divided by real
					numeratorValue = &obj.RealValue{Value: num.Value / denom.Value}
				}
			}
		}

		return numeratorValue, nil
	}

	// For other operations (+, -, *), evaluate all operands and perform the operation
	evaluatedOperands := make([]obj.Value, len(expr.Operands))
	for i, operand := range expr.Operands {
		value, err := e.Eval(operand)
		if err != nil {
			return nil, err
		}
		evaluatedOperands[i] = value
	}

	// Start with the first operand as the initial result
	result := evaluatedOperands[0]

	// Perform operations with remaining operands
	for i := 1; i < len(evaluatedOperands); i++ {
		nextOperand := evaluatedOperands[i]
		
		switch r := result.(type) {
		case *obj.IntegerValue:
			switch o := nextOperand.(type) {
			case *obj.IntegerValue:
				// Integer operations
				var intResult int64
				switch expr.Operator {
				case "+" :
					intResult = r.Value + o.Value
				case "-" :
					intResult = r.Value - o.Value
				case "*" :
					intResult = r.Value * o.Value
				}
				result = &obj.IntegerValue{Value: intResult}
			case *obj.RationalValue:
				// Convert integer to rational and perform operation
				rRational := &obj.RationalValue{Numerator: r.Value, Denominator: 1}
				result = e.performArithmeticOnRationals(rRational, o, expr.Operator)
			case *obj.RealValue:
				// Convert integer to real and perform operation
				var realResult float64
				switch expr.Operator {
				case "+" :
					realResult = float64(r.Value) + o.Value
				case "-" :
					realResult = float64(r.Value) - o.Value
				case "*" :
					realResult = float64(r.Value) * o.Value
				}
				result = &obj.RealValue{Value: realResult}
			}
		case *obj.RationalValue:
			switch o := nextOperand.(type) {
			case *obj.IntegerValue:
				// Convert integer to rational and perform operation
				oRational := &obj.RationalValue{Numerator: o.Value, Denominator: 1}
				result = e.performArithmeticOnRationals(r, oRational, expr.Operator)
			case *obj.RationalValue:
				// Rational operations
				result = e.performArithmeticOnRationals(r, o, expr.Operator)
			case *obj.RealValue:
				// Convert rational to real and perform operation
				rReal := float64(r.Numerator) / float64(r.Denominator)
				var realResult float64
				switch expr.Operator {
				case "+" :
					realResult = rReal + o.Value
				case "-" :
					realResult = rReal - o.Value
				case "*" :
					realResult = rReal * o.Value
				}
				result = &obj.RealValue{Value: realResult}
			}
		case *obj.RealValue:
			switch o := nextOperand.(type) {
			case *obj.IntegerValue:
				// Real operations with integer
				var realResult float64
				switch expr.Operator {
				case "+" :
					realResult = r.Value + float64(o.Value)
				case "-" :
					realResult = r.Value - float64(o.Value)
				case "*" :
					realResult = r.Value * float64(o.Value)
				}
				result = &obj.RealValue{Value: realResult}
			case *obj.RationalValue:
				// Real operations with rational
				oReal := float64(o.Numerator) / float64(o.Denominator)
				var realResult float64
				switch expr.Operator {
				case "+" :
					realResult = r.Value + oReal
				case "-" :
					realResult = r.Value - oReal
				case "*" :
					realResult = r.Value * oReal
				}
				result = &obj.RealValue{Value: realResult}
			case *obj.RealValue:
				// Real operations
				var realResult float64
				switch expr.Operator {
				case "+" :
					realResult = r.Value + o.Value
				case "-" :
					realResult = r.Value - o.Value
				case "*" :
					realResult = r.Value * o.Value
				}
				result = &obj.RealValue{Value: realResult}
			}
		}
	}

	return result, nil
}

// performArithmeticOnRationals performs arithmetic operations on two rational numbers
func (e *Evaluator) performArithmeticOnRationals(r1, r2 *obj.RationalValue, operator string) obj.Value {
	switch operator {
	case "+" :
		// a/b + c/d = (ad + bc)/bd
		numerator := r1.Numerator*r2.Denominator + r2.Numerator*r1.Denominator
		denominator := r1.Denominator * r2.Denominator
		numReduced, denomReduced := reduceRational(numerator, denominator)
		if denomReduced == 1 {
			return &obj.IntegerValue{Value: numReduced}
		}
		return &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
	case "-" :
		// a/b - c/d = (ad - bc)/bd
		numerator := r1.Numerator*r2.Denominator - r2.Numerator*r1.Denominator
		denominator := r1.Denominator * r2.Denominator
		numReduced, denomReduced := reduceRational(numerator, denominator)
		if denomReduced == 1 {
			return &obj.IntegerValue{Value: numReduced}
		}
		return &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
	case "*" :
		// a/b * c/d = (ac)/(bd)
		numerator := r1.Numerator * r2.Numerator
		denominator := r1.Denominator * r2.Denominator
		numReduced, denomReduced := reduceRational(numerator, denominator)
		if denomReduced == 1 {
			return &obj.IntegerValue{Value: numReduced}
		}
		return &obj.RationalValue{Numerator: numReduced, Denominator: denomReduced}
	default :
		// This should never happen since division is handled separately
		return &obj.IntegerValue{Value: 0}
	}
}

func (e *Evaluator) evalLambda(expr *ast.LambdaExpr) (obj.Value, error) {
	// Convert Symbol parameters to strings
	params := make([]string, len(expr.Parameters))
	for i, param := range expr.Parameters {
		params[i] = param.Value
	}

	// Convert Expression body to []interface{}
	body := make([]interface{}, len(expr.Body))
	for i, stmt := range expr.Body {
		body[i] = stmt
	}

	// Capture the environment without circular references
	// We create a clean environment that only contains non-function values
	// to break potential circular references
	capturedEnv := obj.NewEnvironment()

	// Only capture non-function values to avoid circular references
	if e.env != nil {
		// Create a new environment with the same parent chain
		// but be careful about function references
		capturedEnv = e.env // For now, keep the reference but we'll manage it carefully
	}

	return &obj.FunctionValue{
		Parameters: params,
		Body:       body,
		Env:        capturedEnv,
	}, nil
}

// evalQuote evaluates a quote expression
func (e *Evaluator) evalQuote(q *ast.QuoteExpr) (obj.Value, error) {
	// Convert AST expression to object representation
	return e.astToObject(q.Expression)
}

// astToObject converts an AST expression to an object representation
// This is used for quote expressions to return the expression as data
func (e *Evaluator) astToObject(expr ast.Expression) (obj.Value, error) {
	switch node := expr.(type) {
	case *ast.StringLiteral:
		return &obj.StringValue{Value: node.Value}, nil
	case *ast.IntegerLiteral:
		return &obj.IntegerValue{Value: node.Value}, nil
	case *ast.BooleanLiteral:
		return &obj.BooleanValue{Value: node.Value}, nil
	case *ast.Symbol:
		return obj.NewSymbolValue(node.Value), nil
	case *ast.List:
		// Empty list
		if len(node.Elements) == 0 {
			return &obj.NilValue{}, nil
		}
		// Build list as cons pairs
		var result, current *obj.PairValue
		for i, element := range node.Elements {
			value, err := e.astToObject(element)
			if err != nil {
				return nil, err
			}
			pair := &obj.PairValue{Car: value}
			if i == 0 {
				result = pair
				current = pair
			} else {
				current.Cdr = pair
				current = pair
			}
		}
		// Set the last cdr to nil
		current.Cdr = &obj.NilValue{}
		return result, nil
	case *ast.FunctionCall:
		// Treat function call as a list when in quote expression
		// Convert function and arguments to a list
		listElements := []ast.Expression{node.Function}
		listElements = append(listElements, node.Arguments...)
		list := &ast.List{Elements: listElements}
		return e.astToObject(list)
	default:
		return nil, fmt.Errorf("cannot convert %T to object", expr)
	}
}

func (e *Evaluator) evalFunctionCall(call *ast.FunctionCall) (obj.Value, error) {
	function, err := e.Eval(call.Function)
	if err != nil {
		return nil, err
	}

	// Handle builtin functions
	if builtin, ok := function.(*obj.BuiltinValue); ok {
		// Evaluate all arguments
		args := make([]obj.Value, len(call.Arguments))
		for i, arg := range call.Arguments {
			args[i], err = e.Eval(arg)
			if err != nil {
				return nil, err
			}
		}
		// Call the appropriate function based on whether it requires the evaluator
		if builtin.RequiresEvaluator {
			return builtin.EvaluatorAwareFn(e, args)
		} else {
			return builtin.Fn(args)
		}
	}

	fn, ok := function.(*obj.FunctionValue)
	if !ok {
		return nil, fmt.Errorf("not a function")
	}

	if len(call.Arguments) != len(fn.Parameters) {
		return nil, fmt.Errorf("argument count mismatch")
	}

	// Create new environment for function execution
	newEnv := obj.NewEnclosedEnvironment(fn.Env)

	// Bind arguments to parameters
	for i, param := range fn.Parameters {
		arg, err := e.Eval(call.Arguments[i])
		if err != nil {
			return nil, err
		}
		newEnv.Set(param, arg)
	}

	// Evaluate function body in new environment
	oldEnv := e.env
	e.env = newEnv
	defer func() {
		e.env = oldEnv
		// Help with garbage collection by clearing the temporary environment
		newEnv.Clear()
	}()

	var result obj.Value = &obj.NilValue{}
	for _, stmt := range fn.Body {
		result, err = e.Eval(stmt)
		if err != nil {
			return nil, err
		}
	}

	return result, nil
}
